package com.faxsun.core.utils;

/*******************************************************************************
 * Copyright (c) 2014, 2015 mtons.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * 
 * Copyright (c) 2015, faxsun.com
 *******************************************************************************/

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

import org.htmlparser.Node;
import org.htmlparser.Parser;
import org.htmlparser.lexer.Lexer;
import org.htmlparser.lexer.Page;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.nodes.TextNode;
import org.htmlparser.tags.ImageTag;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeIterator;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.springframework.util.StringUtils;

/**
 * HTML截取器
 * 
 * @author langhsu
 * @author songdragon 2015-05-19 添加忽略strong标签
 *
 */
public class PreviewHtmlUtils {

	/**
	 * 截取html子串
	 * 
	 * @param html
	 *            html文本
	 * @param length
	 *            最大子串长度（不含html标签）
	 * @param trim
	 *            截取时忽略不必要的html标签属性
	 * @return
	 */
	public static String truncateHTML(String html, int length) {
		if (StringUtils.isEmpty(html)) {
			return "";
		}
		return new HtmlCropper(html, length).substr();
	}

	/**
	 *
	 * HTML截取器
	 * 
	 * 用于对HTML文档执行类似substring的操作，保证截取后的html格式可以自动封闭
	 *
	 */
	static class HtmlCropper {
		protected final Parser parser;
		protected final StringBuilder buf;

		private static Set<String> ignores = toSet("SCRIPT", "STYLE");
		private static Set<String> trimAttrs = toSet("PRE", "DIV", "LABEL",
				"VAR", "CENTER", "B", "I", "FONT", "DEL", "P");
		private static Set<String> trimTags = toSet("STRONG", "BIG", "SPAN",
				"A","EM");
		private final int maxLen;
		private int subLen = 0;

		private static Set<String> toSet(String... args) {
			HashSet<String> s = new HashSet<String>(args.length);
			for (String v : args) {
				s.add(v);
			}
			return s;
		}

		public HtmlCropper(String html, int length) {
			this.parser = new Parser(new Lexer(new Page(html, "utf-8")),
					Parser.STDOUT);
			this.maxLen = length;
			this.buf = new StringBuilder(length * 2);
		}

		public String substr() {
			try {
				NodeIterator itr = parser.elements();
				while (itr.hasMoreNodes() && !isEnd()) {
					handle(itr.nextNode());
				}
			} catch (ParserException e) {
			}

			return buf.toString();
		}

		private boolean isEnd() {
			return this.subLen >= this.maxLen;
		}

		private void handle(Node node) throws ParserException {
			if (node instanceof TagNode) {
				TagNode tag = (TagNode) node;
				if (tag.getEndTag() == null) {
					if (tag instanceof ImageTag) {
						// handleImage((ImageTag) tag);
					} else {
						if (!trimTags.contains(tag.getTagName()))
							buf.append(tag.toHtml());
					}
				} else {
					handleTag(tag);
				}
			} else if (node instanceof TextNode) {
				handleText((TextNode) node);
			}
		}

		protected void handleText(TextNode t) {
			String text = t.getText().trim();
			if (text.length() == 0) {
				return;
			}

			int len = text.length();
			if (len + subLen > maxLen) {
				buf.append(text.substring(0, maxLen - subLen)).append(" ...");
			} else {
				buf.append(text);
			}
			subLen += len;
		}

		private void handleTag(TagNode tag) throws ParserException {
			String name = tag.getTagName();
			if (ignores.contains(name)) {
				return;
			}

			if (trimAttrs.contains(name)) {
				buf.append('<').append(name).append('>');
			} else if (trimTags.contains(name)) {
			} else if ("A".equals(name)) {
				handleLink((LinkTag) tag);
			} else {
				buf.append('<').append(tag.getText()).append('>');
			}

			NodeList nl = tag.getChildren();
			if (nl != null) {
				NodeIterator itr = nl.elements();
				while (itr.hasMoreNodes() && !isEnd()) {
					handle(itr.nextNode());
				}
			}
			if (!trimTags.contains(name))
				buf.append("</").append(name).append('>');
			int emptyParagraph = buf.lastIndexOf("<P></P>");
			if (emptyParagraph >= 0) {
				buf.delete(emptyParagraph, emptyParagraph + 7);
			}
		}

		protected void handleLink(LinkTag t) {
			buf.append("<A href=\"").append(t.getLink()).append("\">");
		}

		protected void handleImage(ImageTag t) {
			buf.append("<IMG src=\"").append(t.getImageURL()).append("\"/>");
			// 修正文字长度，防止没有内容只有图片的情况
			this.subLen += 50;
		}
	}

	/**
	 * 删除Html标签
	 * 
	 * @param inputString
	 * @return
	 */
	public static String htmlRemoveTag(String inputString) {
		if (inputString == null)
			return null;
		String htmlStr = inputString; // 含html标签的字符串
		String textStr = "";
		java.util.regex.Pattern p_script;
		java.util.regex.Matcher m_script;
		java.util.regex.Pattern p_style;
		java.util.regex.Matcher m_style;
		java.util.regex.Pattern p_html;
		java.util.regex.Matcher m_html;
		try {
			// 定义script的正则表达式{或<script[^>]*?>[\\s\\S]*?<\\/script>
			String regEx_script = "<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>";
			// 定义style的正则表达式{或<style[^>]*?>[\\s\\S]*?<\\/style>
			String regEx_style = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>";
			String regEx_html = "<[^>]+>"; // 定义HTML标签的正则表达式
			p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
			m_script = p_script.matcher(htmlStr);
			htmlStr = m_script.replaceAll(""); // 过滤script标签
			p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
			m_style = p_style.matcher(htmlStr);
			htmlStr = m_style.replaceAll(""); // 过滤style标签
			p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
			m_html = p_html.matcher(htmlStr);
			htmlStr = m_html.replaceAll(""); // 过滤html标签
			textStr = htmlStr;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return textStr;// 返回文本字符串
	}
}
